/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = ora_core.c                                         */
/*  NOTE      =                                                    */
/*  DATE      = 2014/09/26 by songbb                               */
/*******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>

#include "frcomm.h"
#include "frstr.h"
#include "frhash2.h"
#include "frmem.h"
#include "frlog.h"
#include "frsutl.h"

#include "conntrack.h"
#include "frct_comm.h"
#include "frversion.h"
#include "frservice_comm.h"

#include "config.h"
#include "ora_core.h"

#include "comm/ora_comm.h"
#include "comm/ora_util.h"
#include "comm/ora_stmt.h"
#include "tns/ora_packet.h"
#include "tns/ora_accept.h"
#include "tns/ora_connect.h"
#include "tns/ora_redirect.h"
#include "ttc/ora_ttc_proto.h"

#if APM_ORA_DBG
/* 模块全局变量：出错的包的个数 */
FR_STATIC unsigned long long g_ull_ora_error_nums = 0LL;
/* 模块全局变量：未正确解析的分片包的个数 */
FR_STATIC unsigned long long g_ull_ora_unfinshed_fragmented_packets = 0LL;
#endif

//框架的上下文引用
void *g_p_apm_context=NULL;

/*******************************************************************************
*  FUNC     :  累计未正确解析的包个数
*  ARGS     :  *p_st_sess                           (Oracle私有的session)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ora_add_error_nums(L7session_ora *p_st_sess)
{
#if APM_ORA_DBG
    g_ull_ora_error_nums++;
#endif
    if (p_st_sess != NULL)
        p_st_sess->ull_error_nums++;
    return;
}

/*******************************************************************************
*  FUNC     :  累计未正确解析的分片包个数
*  ARGS     :  *p_st_sess                           (Oracle私有的session)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void ora_core_add_unfinshed_fragmented_packets(L7session_ora *p_st_sess)
{
#if APM_ORA_DBG
    g_ull_ora_unfinshed_fragmented_packets++;
#endif
    if (p_st_sess != NULL)
        p_st_sess->ull_unfinshed_fragmented_packets++;
    return;
}

/*******************************************************************************
*  FUNC     :  打印ct上记录的调试信息
*  ARGS     :  *p_st_private                        (Oracle的私有信息)
*           :  *p_st_sess                           (Oracle私有的session)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ora_print_ct_dbg_info(L7session_ora_private *p_st_private
                                       , L7session_ora *p_st_sess)
{
    if (p_st_private == NULL || p_st_sess == NULL)
        return;

    if (p_st_sess->i_ttc8_long_analyze_succ == FR_NO)
        ORA_FRLOG_ERROR("analyze long connect failed, packets in:[%llu], session id:[%s]", p_st_sess->ull_packets_in, p_st_private->p_st_session->arr_session_id);

    if (p_st_sess->ull_error_nums > 0LL || p_st_sess->ull_unfinshed_fragmented_packets > 0LL)
    {
        if (p_st_sess->ull_error_nums > 0LL)
            ORA_PRINT_NOTICE("session errors num:[%llu], session id:[%s]\n", p_st_sess->ull_error_nums, p_st_private->p_st_session->arr_session_id);
        if (p_st_sess->ull_unfinshed_fragmented_packets > 0LL)
            ORA_PRINT_NOTICE("session unfinshed fragmented packets num:[%llu], session id:[%s]\n", p_st_sess->ull_unfinshed_fragmented_packets, p_st_private->p_st_session->arr_session_id);
    }
    else
        ORA_PRINT_WARN("session success\n\n");

    return;
}

/*******************************************************************************
*  FUNC     :  诊断长连接时的情况，每过500个包还没正确分析出长连接参数时，则写日志信息
*  ARGS     :  *p_st_session                        (L7层session信息)
*           :  *p_st_sess                           (Oracle私有的session)
*           :  st_timestamp                         (当前包的时间)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ora_diagnosis_long_connect(L7_session *p_st_session
                                            , L7session_ora *p_st_sess
                                            , struct timeval st_timestamp)
{
    char arr_time_buff[16];

    if (p_st_session == NULL || p_st_sess == NULL)
        return;

    if (p_st_sess->i_ttc8_long_analyze_succ == FR_NO && p_st_sess->ull_packets_in % 500 == 0)
    {
        if (ora_util_frtime2timestr(&st_timestamp, arr_time_buff, sizeof(arr_time_buff)) != FR_SUCC)
            return;
        ORA_FRLOG_ERROR("analyze long connect failed, packets in:[%llu], timenow:[%s], session id:[%s]",
                           p_st_sess->ull_packets_in,
                           arr_time_buff,
                           p_st_session->arr_session_id);
    }

    return;
}

/*******************************************************************************
*  FUNC     :  打印模块的调试信息
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ora_print_dbg_info()
{
#if APM_ORA_DBG
    if (g_ull_ora_error_nums > 0LL || g_ull_ora_unfinshed_fragmented_packets > 0LL)
    {
        if (g_ull_ora_error_nums > 0LL)
            ORA_PRINT_WARN("module errors num:[%llu]\n\n", g_ull_ora_error_nums);
        if (g_ull_ora_unfinshed_fragmented_packets > 0LL)
            ORA_PRINT_WARN("module unfinshed fragmented packets num:[%llu]\n\n", g_ull_ora_unfinshed_fragmented_packets);
    }
    else
        ORA_PRINT_WARN("module success\n\n");
#endif
    return;
}

/*******************************************************************************
*  FUNC     :  Oracle Session初始化
*  ARGS     :  *p_st_session            (L7层session信息)
*  RTN      :  0                        (FR_SUCC)
*              1                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __ora_private_session_init(L7_session *p_st_session)
{
    ORA_PRINT_INFO("session init\n");
    L7session_ora_private *p_st_oracle_private = NULL;   // Oracle的私有信息
    L7_req_ora *p_st_req = NULL;                         // request数据结构
    L7_resp_ora *p_st_resp = NULL;                       // response数据结构
    L7session_ora *p_st_ora_sess = NULL;                 // Oracle的私有session信息
    L7_ora_packet *p_st_ora_packet = NULL;               // Oracle格式的packet包
    Frhash_header *p_hash_stmt = NULL;                   // Oracle的statement信息结构
    L7_ora_curr_session *p_st_curr_sess = NULL;          // Oracle当前会话的临时性数据

    // 1. 初始化Oracle的私有session信息
    if ((p_st_ora_sess = (L7session_ora *) frmalloc(sizeof(L7session_ora))) == NULL)
    {
        ORA_MALLOCK_ERR;
        goto error;
    }
    memset(p_st_ora_sess, 0x00, sizeof(L7session_ora));
    ora_set_ttc_type_rep_jdbc(p_st_ora_sess);
    ora_set_ttc_type_rep(p_st_ora_sess, 1, 2);
    ora_reset_sess_phase(p_st_ora_sess->arr_sess_phase);
    p_st_ora_sess->i_charset_assumed                  = FR_NO;
    p_st_ora_sess->s_tns_version_req                  = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->s_tns_version                      = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->s_negotiated_options               = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_cli_is_bigendian                 = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_srv_is_bigendian                 = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->c_conversion_flags                 = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_is_large_sdu                     = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_srv_conversion                   = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->c_ttc_version                      = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_useCLR_big_chunks                = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_useLobPrefetch                   = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->c_pro_srv_version                  = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->s_version_number                   = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_pool_enabled                     = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ptr_len                          = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_use_oci                          = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_use_special_field                = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_send_typerep                     = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_c2snlsratio                      = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_oci_stmt_req_skip4_ttc7          = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_oci_stmt_req_skip4_ttc8          = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_oci_oversion_skip4               = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->c_ttc_api_version                  = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->p_list_closed_cursors              = frlist_create();

    p_st_ora_sess->i_CHR_conversion_flags             = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc7_oactoid                     = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc7_rxhrqsts                    = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_long_analyze_succ           = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_req_i                  = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_req_j                  = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_req_dml                = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_req_oci_after_dml      = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_dcb_recv          = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_oac_skip1         = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_oac_skipaftervsn  = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_udskpos           = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_udsflg            = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_dcbkm             = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_dcbni1            = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_dcbab2            = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_rpag              = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_rpadml            = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_oereocs           = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_oerendseq         = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_oeraij            = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_oci_oerskip8      = APM_ORA_FLAG_UNSET;
    p_st_ora_sess->i_ttc8_stmt_resp_oci_oerskip6      = APM_ORA_FLAG_UNSET;

    #if APM_ORA_DBG
    p_st_ora_sess->st_timestamp.tv_sec = 0L;
    p_st_ora_sess->st_timestamp.tv_usec = 0L;
    #endif


    // 2. 初始化response数据结构
    if ((p_st_req = (L7_req_ora *) frmalloc(sizeof(L7_req_ora))) == NULL)
    {
        ORA_MALLOCK_ERR;
        goto error;
    }
    memset(p_st_req, 0x00, sizeof(L7_req_ora));
    p_st_req->p_st_list_ttc7_stmt = frlist_create();

    // 3. 初始化response数据结构
    if ((p_st_resp = (L7_resp_ora *) frmalloc(sizeof(L7_resp_ora))) == NULL)
    {
        ORA_MALLOCK_ERR;
        goto error;
    }
    memset(p_st_resp, 0x00, sizeof(L7_resp_ora));
    ora_reset_resp_info(p_st_resp);

    // 4. 初始化Oracle格式的packet包
    if ((p_st_ora_packet = (L7_ora_packet *) frmalloc(sizeof(L7_ora_packet))) == NULL)
    {
        ORA_MALLOCK_ERR;
        goto error;
    }
    memset(p_st_ora_packet, 0x00, sizeof(L7_ora_packet));
    if (ora_init_ora_packet(p_st_ora_packet) != FR_SUCC)
        goto error;

    // 5. 初始化Oracle的statement信息结构
    if ((p_hash_stmt = (Frhash_header *) frmalloc(sizeof(Frhash_header))) == NULL)
    {
        ORA_MALLOCK_ERR;
        goto error;
    }
    memset(p_hash_stmt, 0x00, sizeof(Frhash_header));
    if (frhash2_create(p_hash_stmt, APM_ORA_HASH_SIZE) != FR_SUCC)
    {
        ORA_FRLOG_ERROR("frhash2_create fail");
        goto error;
    }

    // 6. 初始化当前会话的数据
    if ((p_st_curr_sess = (L7_ora_curr_session *) frmalloc(sizeof(L7_ora_curr_session))) == NULL)
    {
        ORA_MALLOCK_ERR;
        goto error;
    }
    memset(p_st_curr_sess, 0x00, sizeof(L7_ora_curr_session));
    p_st_curr_sess->ul_cursor = (unsigned long) APM_ORA_FLAG_UNSET;

    // 7. 创建和初始化Oracle的私有信息
    if ((p_st_oracle_private = (L7session_ora_private *) frmalloc(sizeof(L7session_ora_private))) == NULL)
    {
        ORA_MALLOCK_ERR;
        goto error;
    }
    memset(p_st_oracle_private, 0x00, sizeof(L7session_ora_private));
    p_st_oracle_private->p_st_sess = p_st_ora_sess;
    p_st_oracle_private->p_st_req = p_st_req;
    p_st_oracle_private->p_st_resp = p_st_resp;
    p_st_oracle_private->p_st_ora_packet = p_st_ora_packet;
    p_st_oracle_private->p_hash_stmt = p_hash_stmt;
    p_st_oracle_private->p_st_curr_sess = p_st_curr_sess;
    p_st_oracle_private->p_st_session = p_st_session;

    // 8. 设置L7_session的p_session_private信息
    frct_set_session_private(p_st_session, (void *)p_st_oracle_private);

    return FR_SUCC;
error:
    ora_free((void **) &p_st_ora_sess);
    ora_free((void **) &p_st_req);
    ora_free((void **) &p_st_resp);
    if (p_st_ora_packet != NULL)
    {
        bytebuff_free(&(p_st_ora_packet->p_st_packet));
        ora_free((void **) &(p_st_ora_packet->p_payload_left));
    }
    ora_free((void **) &p_st_ora_packet);
    frhash2_free(p_hash_stmt, frdb_statement_node_free);
    ora_free((void **) &p_hash_stmt);
    ora_free((void **) &p_st_curr_sess);
    ora_free((void **) &p_st_oracle_private);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  释放 L7session_ora
*  ARGS     :  **pp_st_session              (L7session_ora)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ora_destroy_session(L7session_ora **pp_st_session)
{
    if (pp_st_session == NULL || *pp_st_session == NULL)
        return;

    L7session_ora *p_st_sess = *pp_st_session;
    ora_free((void **) &(p_st_sess->p_db_sid));
    ora_free((void **) &(p_st_sess->p_program));
    ora_free((void **) &(p_st_sess->p_client_hostname));
    ora_free((void **) &(p_st_sess->p_username));
    ora_free((void **) &(p_st_sess->p_srv_compile_time_capabilities));
    ora_free((void **) &(p_st_sess->p_CTcap));
    ora_free((void **) &(p_st_sess->p_RTcap));
    frlist_destroy(p_st_sess->p_list_closed_cursors, frlist_node_data_free);
    ora_free((void **) pp_st_session);
    return;
}

/*******************************************************************************
*  FUNC     :  释放 L7_req_ora
*  ARGS     :  **pp_st_req              (L7_req_ora)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ora_destroy_request(L7_req_ora **pp_st_req)
{
    if (pp_st_req == NULL || *pp_st_req == NULL)
        return;

    L7_req_ora *p_st_req = *pp_st_req;
    frdb_statement_free(&(p_st_req->p_st_stmt));
    ora_free((void **) &(p_st_req->p_st_stmt));
    frlist_destroy(p_st_req->p_st_list_ttc7_stmt, frdb_statement_node_free);
    ora_free((void **) pp_st_req);
    return;
}

/*******************************************************************************
*  FUNC     :  释放 L7_resp_ora
*  ARGS     :  **pp_st_resp              (L7_resp_ora)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ora_destroy_response(L7_resp_ora **pp_st_resp)
{
    if (pp_st_resp == NULL || *pp_st_resp == NULL)
        return;

    L7_resp_ora *p_st_resp = *pp_st_resp;
    ora_free((void **) &(p_st_resp->p_response_codestring));
    ora_free((void **) &(p_st_resp->p_response_error_mesg));
    ora_free((void **) pp_st_resp);
    return;
}

/*******************************************************************************
*  FUNC     :  释放 L7_ora_fragment
*  ARGS     :  **pp_st_fragment              (L7_ora_fragment)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ora_destroy_ora_packet(L7_ora_packet **pp_st_ora_packet)
{
    if (pp_st_ora_packet == NULL || *pp_st_ora_packet == NULL)
        return;

    L7_ora_packet *p_st_ora_packet = *pp_st_ora_packet;
    bytebuff_free(&(p_st_ora_packet->p_st_packet));
    ora_free((void **) &(p_st_ora_packet->p_payload_left));
    ora_free((void **) pp_st_ora_packet);
    return;
}

/*******************************************************************************
*  FUNC     :  释放 L7_ora_curr_session
*  ARGS     :  **pp_st_curr_session              (L7_ora_curr_session)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ora_destroy_curr_session(L7_ora_curr_session **pp_st_curr_session)
{
    if (pp_st_curr_session == NULL || *pp_st_curr_session == NULL)
        return;

    L7_ora_curr_session *p_st_curr_session = *pp_st_curr_session;
    ora_free((void **) &(p_st_curr_session->p_ll_rows));
    ora_free((void **) pp_st_curr_session);
    return;
}

/*******************************************************************************
*  FUNC     :  释放Oracle private数据
*  ARGS     :  *p_st_session_private_in                 (Oracle的私有信息)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
FR_STATIC int ora_session_destory(void *p_st_session_private_in)
{
    ORA_PRINT(KBLUE "\nora_session_destory run\n" RESET);
    if (p_st_session_private_in == NULL)
        return FR_SUCC;

    L7session_ora_private *p_st_private = (L7session_ora_private *) p_st_session_private_in;

    ORA_PRINT_SESS(p_st_private->p_st_sess);

    __ora_print_ct_dbg_info(p_st_private, p_st_private->p_st_sess);

    // 销毁Oracle session信息
    __ora_destroy_session(&(p_st_private->p_st_sess));

    // 销毁request信息
    __ora_destroy_request(&(p_st_private->p_st_req));

    // 销毁response信息
    __ora_destroy_response(&(p_st_private->p_st_resp));

    // 销毁Oracle packet信息
    __ora_destroy_ora_packet(&(p_st_private->p_st_ora_packet));

    // 销毁Oracle当前会话的临时性数据
    __ora_destroy_curr_session(&(p_st_private->p_st_curr_sess));

    // 销毁statement数据信息
    ora_free_private_stmt(p_st_private);

    ora_free((void **) &p_st_private);

    ORA_PRINT_INFO("leave ora_session_destory\n");
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  判断当前数据链路是否是Oracle协议的
*  ARGS     :  *p_st_conn  (ct信息)
            :  *p_data     (实际要解析的数据)
            :  ui_len      (数据长度)
*  RTN      :  0       (normal)
*              1       (error)
*  NOTE     :
*******************************************************************************/
FR_STATIC int ora_detect(Conntrack *p_st_conn
                        , Apm_packet *p_st_packet)
{
    ORA_PRINT_INFO("ora_detect\n");
    int i_large_sdu_flag = 0;

    if(p_st_packet == NULL || p_st_packet->p_payload == NULL || p_st_packet->ui_payload_len == 0 || p_st_conn==NULL)
        return APM_L7_IS_NO;

#if APM_ORA_DBG
    char arr_ip_src[56], arr_ip_dst[56];
    snprintf(arr_ip_src, sizeof(arr_ip_src), "%s", int_ntoa(p_st_packet->src_ip));
    snprintf(arr_ip_dst, sizeof(arr_ip_src), "%s", int_ntoa(p_st_packet->dst_ip));
    ORA_PRINT_TIMEVAL("PacketIn", p_st_packet->st_timestamp);
    ORA_PRINT_DBG("Src:[%s:%d] Dest:[%s:%d] Length:[%u]\n", arr_ip_src, p_st_packet->src_port, arr_ip_dst, p_st_packet->dst_port, p_st_packet->ui_payload_len);
#endif

    int i_ret = ora_header_detect(p_st_packet->p_payload, p_st_packet->ui_payload_len, &i_large_sdu_flag);
    if (i_ret != APM_L7_IS_YES && p_st_packet->ui_payload_len != 0) //使用协议判断不成功时，使用保存的服务器信息进行判断
    {
        if (p_st_packet->i_direction == FR_DIRECT_UNKNOWN || frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
        {
            if (frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL) == FR_SUCC)
            {
                ORA_PRINT_ALERT("frservice_get success:[%s:%d]\n", arr_ip_dst, p_st_packet->dst_port);
                if (frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port) != FR_SUCC)
                    return APM_L7_IS_UNKNOWN;
                i_ret = APM_L7_IS_YES;
            }
            else if (frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL) == FR_SUCC)
            {
                ORA_PRINT_ALERT("frservice_get success:[%s:%d]\n", arr_ip_src, p_st_packet->src_port);
                if (frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port) != FR_SUCC)
                    return APM_L7_IS_UNKNOWN;
                i_ret = APM_L7_IS_YES;
            }
        }
        else
        {
            if (frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL) == FR_SUCC)
            {
                ORA_PRINT_ALERT("frservice_get success:[%s:%d]\n", arr_ip_dst, p_st_packet->dst_port);
                if (frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port) != FR_SUCC)
                    return APM_L7_IS_UNKNOWN;
                i_ret = APM_L7_IS_YES;
            }
        }
    }
    if (i_ret == APM_L7_IS_YES)
    {
        if (p_st_packet->i_direction == FR_DIRECT_UNKNOWN || frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
        {
            if (p_st_packet->src_port == APM_ORA_DEFAULT_PORT && p_st_packet->dst_port != APM_ORA_DEFAULT_PORT)
            {
                if (frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port) != FR_SUCC)
                    return APM_L7_IS_UNKNOWN;
            }
            else if (p_st_packet->src_port != APM_ORA_DEFAULT_PORT && p_st_packet->dst_port == APM_ORA_DEFAULT_PORT)
            {
                if (frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port) != FR_SUCC)
                    return APM_L7_IS_UNKNOWN;
            }
            else
                return APM_L7_IS_UNKNOWN;
        }
    }

    if (i_ret == APM_L7_IS_UNKNOWN)
        ORA_PRINT_ERR("detect unknown\n\n");
    else
        ORA_PRINT_ERR("detect yes\n\n");

    return i_ret;
}

/*******************************************************************************
*  FUNC     :  Oracle协议解析
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_packet                        (协议分析入力数据)
*           :  *p_st_hash_report                    (保存Frreport_data)
*  RTN      :  参照module.h中APM_L7_ANALYZE_的定义
*  NOTE     :
*******************************************************************************/
FR_STATIC int ora_analyze(Conntrack *p_st_conn
                        , Apm_packet *p_st_analyze_in
                        , Frhash_header *p_st_hash_report)
{
    ORA_PRINT_INFO("ora_analyze\n");
    L7_session *p_st_session = NULL;
    L7session_ora_private *p_st_session_private = NULL;
    L7session_ora *p_st_sess = NULL;
    L7_ora_packet *p_st_ora_packet = NULL;
    int i_prepare_data_ret = 0;
    int i_analyze_ret = 0;                  // 本函数的返回值
    int i_this_func_ret = 0;
#if APM_ORA_DBG
    char arr_ip_src[56], arr_ip_dst[56];
    snprintf(arr_ip_src, sizeof(arr_ip_src), "%s", int_ntoa(p_st_analyze_in->src_ip));
    snprintf(arr_ip_dst, sizeof(arr_ip_src), "%s", int_ntoa(p_st_analyze_in->dst_ip));
#endif

    if(p_st_conn == NULL || p_st_analyze_in == NULL
        || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_session = frct_get_session(p_st_conn);

#if APM_ORA_DBG
    ORA_PRINT_TIMEVAL("PacketIn", p_st_analyze_in->st_timestamp);
    ORA_PRINT_DBG("Src:[%s:%d] Dest:[%s:%d] SessionID:[%s]\n", arr_ip_src, p_st_analyze_in->src_port, arr_ip_dst, p_st_analyze_in->dst_port, p_st_session->arr_session_id);
#endif

    switch (p_st_analyze_in->i_direction)
    {
        case FR_DIRECT_CLIENT2SRV:
#if APM_ORA_DBG
            ORA_PRINT("3 client["KLIMEGREEN"%s:%d"RESET"] to server["KLIMEGREEN"%s:%d"RESET"] ["KYELLOW"%d"RESET"] ->>>>>>>>>>>>>>>>>>>>>>>\n",
                      arr_ip_src,
                      p_st_analyze_in->src_port,
                      arr_ip_dst,
                      p_st_analyze_in->dst_port,
                      p_st_analyze_in->ui_payload_len);
#endif
            break;
        case FR_DIRECT_SRV2CLIENT:
#if APM_ORA_DBG
            ORA_PRINT("4 server["KLIMEGREEN"%s:%d"RESET"] to client["KLIMEGREEN"%s:%d"RESET"] ["KYELLOW"%d"RESET"] <<<<<<<<<<<<<<<<<<<<<<<-\n",
                      arr_ip_src,
                      p_st_analyze_in->src_port,
                      arr_ip_dst,
                      p_st_analyze_in->dst_port,
                      p_st_analyze_in->ui_payload_len);
#endif
            break;
        default:
#if APM_ORA_DBG
            ORA_PRINT("unknown direction, src["KLIMEGREEN"%s:%d"RESET"], dest["KLIMEGREEN"%s:%d"RESET"]\n",
                      arr_ip_src,
                      p_st_analyze_in->src_port,
                      arr_ip_dst,
                      p_st_analyze_in->dst_port);
#endif
            goto ora_analyze_fail;
    }

    /*
    * 如果入力p_st_analyze_in是FIN包, 说明本次connection结束,
    * 释放本次session信息. 如果入力p_st_analyze_in是SYN包,说明新的
    * connection开始了, 释放上次可能残留的session信息
    */
    if (p_st_analyze_in->em_analyz_cmd == FRANALYZ_CMD_FIN || p_st_analyze_in->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        if (p_st_analyze_in->em_analyz_cmd == FRANALYZ_CMD_SYN)
            ORA_PRINT_INFO("SYN PACKET\n");
        else if (p_st_analyze_in->em_analyz_cmd == FRANALYZ_CMD_FIN)
        {
            ORA_PRINT_INFO("FIN PACKET\n");
            if (p_st_session->p_session_private != NULL && ((L7session_ora_private *)(p_st_session->p_session_private))->p_st_sess != NULL)
                ora_report_all_stmt(p_st_conn, ((L7session_ora_private *)(p_st_session->p_session_private))->p_st_sess, p_st_hash_report);
        }
        if (p_st_session->p_session_private != NULL)
        {
            ora_session_destory((void *) (p_st_session->p_session_private));
            p_st_session->p_session_private = NULL;
        }
        ORA_PRINT("### i_analyze_ret:[%d]\n\n", APM_L7_ANALYZE_SUCC);
        return APM_L7_ANALYZE_SUCC;
    }

    /* 本次链路的第一个有效packet包,创建链路 */
    if (p_st_session->p_session_private == NULL)
    {
        // 初始化Oracle的session数据
        if (__ora_private_session_init(p_st_session) != FR_SUCC)
            goto ora_analyze_fail;

        // 设置session uuid
        fruuid(p_st_session->arr_session_id);
    }

    p_st_session_private = (L7session_ora_private *) frct_get_session_private(p_st_session);
    p_st_sess = p_st_session_private->p_st_sess;
    p_st_ora_packet = p_st_session_private->p_st_ora_packet;

    p_st_sess->ull_packets_in++;
    __ora_diagnosis_long_connect(p_st_session, p_st_sess, p_st_analyze_in->st_timestamp);

    i_prepare_data_ret = ora_packet_prepare_data(p_st_sess, p_st_analyze_in, p_st_ora_packet);
    if (i_prepare_data_ret == APM_ORA_CHECK_FRAGMENT_NEED_NEXT_PACKET)
        goto ora_analyze_todo;
    else if (i_prepare_data_ret == APM_ORA_CHECK_FRAGMENT_ERROR)
        goto ora_analyze_fail;

#if APM_ORA_SUPPORT_OCI == 0
    if (p_st_sess->i_use_special_field == FR_YES)
    {
        ORA_PRINT_CRIT("NOT SUPPORT OCI\n");
        goto ora_analyze_fail;
    }
#endif

    switch (p_st_ora_packet->tns_type)
    {
        case APM_ORA_TNS_TYPE_CONNECT:
            ORA_PRINT_INFO("tns connect request\n");
            if (ora_connect_unpack(p_st_conn, p_st_sess, p_st_ora_packet) == FR_SUCC)
            {
                i_analyze_ret = APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
                goto ora_analyze_success;
            }
            goto ora_analyze_fail;

        case APM_ORA_TNS_TYPE_ACCEPT:
            ORA_PRINT_INFO("tns accept response\n");
            if (ora_accept_unpack(p_st_conn, p_st_sess, p_st_ora_packet) == FR_SUCC)
            {
                i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
                goto ora_analyze_success;
            }
            goto ora_analyze_fail;

        case APM_ORA_TNS_TYPE_REDIRECT:
            ORA_PRINT_INFO("tns redirect response\n");
            if (ora_redirect_unpack(p_st_conn, p_st_sess, p_st_ora_packet, p_st_hash_report, p_st_analyze_in) == FR_SUCC)
            {
                i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
                goto ora_analyze_success;
            }
            goto ora_analyze_fail;

        case APM_ORA_TNS_TYPE_DATA:
            if (p_st_analyze_in->i_direction == FR_DIRECT_CLIENT2SRV)
            {
                ORA_PRINT_INFO("tns data request\n");
                i_this_func_ret = ora_ttc_proto_analyze_req(p_st_conn, p_st_sess, p_st_ora_packet, p_st_hash_report);
            }
            else if (p_st_analyze_in->i_direction == FR_DIRECT_SRV2CLIENT)
            {
                ORA_PRINT_INFO("tns data response\n");
                i_this_func_ret = ora_ttc_proto_analyze_resp(p_st_conn, p_st_sess, p_st_ora_packet, p_st_hash_report, p_st_analyze_in);
            }
            else
            {
                ORA_PRINT_EMERG("Do not know the direction of connection\n");
                ORA_FRLOG_ERROR("Do not know the direction of connection");
                goto ora_analyze_fail;
            }
            if (i_this_func_ret != APM_L7_ANALYZE_FAIL)
            {
                i_analyze_ret = i_this_func_ret;
                goto ora_analyze_success;
            }
            goto ora_analyze_fail;

        case APM_ORA_TNS_TYPE_ACK:          // ignored
            ORA_PRINT_INFO("tns ack\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto ora_analyze_success;

        case APM_ORA_TNS_TYPE_REFUSE:       // ignored
            ORA_PRINT_INFO("tns refuse\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto ora_analyze_success;

        case APM_ORA_TNS_TYPE_NULL:         // ignored
            if (p_st_ora_packet->us_dataflag & 0x40) // disconnect
            {
                ORA_PRINT_INFO("disconnect\n");
                ora_report_all_stmt(p_st_conn, p_st_sess, p_st_hash_report);
            }
            else
                ORA_PRINT_INFO("tns null\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto ora_analyze_success;

        case APM_ORA_TNS_TYPE_ABORT:        // ignored
            ORA_PRINT_INFO("tns abort\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto ora_analyze_success;

        case APM_ORA_TNS_TYPE_RESEND:       // ignored
            ORA_PRINT_INFO("tns resend\n");
            APM_ORA_SET_PHASE_P_RESEND(p_st_sess->ull_bits_phase_progress);
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto ora_analyze_success;

        case APM_ORA_TNS_TYPE_MARKER:       // ignored
            ORA_PRINT_INFO("tns marker\n");
            ora_remaining_last_sess_phase(p_st_sess->arr_sess_phase);
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto ora_analyze_success;

        case APM_ORA_TNS_TYPE_ATTENTION:    // ignored
            ORA_PRINT_INFO("tns attention\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto ora_analyze_success;

        case APM_ORA_TNS_TYPE_CONTROL:      // ignored
            ORA_PRINT_INFO("tns control\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto ora_analyze_success;

        case APM_ORA_TNS_TYPE_DATADESC:      // ignored
            ORA_PRINT_INFO("tns datadescriptor\n");
            i_analyze_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            goto ora_analyze_success;

        default:
            ORA_PRINT_EMERG("invalid tns type:[%d]\n", p_st_ora_packet->tns_type);
            ORA_FRLOG_ERROR("invalid tns type:[%d]", p_st_ora_packet->tns_type);
            goto ora_analyze_fail;
    }

ora_analyze_todo:
    ORA_PRINT("### i_analyze_ret todo:[%d]\n\n", APM_L7_ANALYZE_TODO);
    return APM_L7_ANALYZE_TODO;

ora_analyze_success:
    ORA_PRINT("### i_analyze_ret success:[%d]\n\n", i_analyze_ret);
    return i_analyze_ret;

ora_analyze_fail:
    if (ora_packet_is_in_fragment(p_st_ora_packet))
    {
        if (bytebuff_setPosition(p_st_ora_packet->p_st_packet, 0) != FR_SUCC)
        {
            p_st_ora_packet->fragment_state = APM_ORA_FRAGMENT_INIT;
            return APM_L7_ANALYZE_FAIL;
        }
        goto ora_analyze_todo;
    }
    else
    {
        __ora_add_error_nums(p_st_sess);
        ORA_PRINT_PACKET("error packet", p_st_ora_packet);
        ora_init_ora_packet(p_st_ora_packet);
    }

    ORA_PRINT_EMERG("### i_analyze_ret fail:[%d]\n\n", APM_L7_ANALYZE_FAIL);
    return APM_L7_ANALYZE_FAIL;
}

#ifdef  __cplusplus
extern "C"
{
#endif

/*******************************************************************************
*  FUNC     :  oracle初始化
*  ARGS     :  p_context                    框架的上下文引用
*           :  p_module_params              模块入力参数
*           :  p_module_cfg                 模块配置信息出力
*  RTN      :  FR_FAIL
*           :  FR_SUCC
*  NOTE     :
*******************************************************************************/
int module_init(void *p_context, const char* p_module_params, L7_module_config *p_module_cfg)
{
    ORA_PRINT_INFO("ora_init\n");

    if(p_context == NULL || p_module_cfg == NULL)
        return FR_FAIL;

    g_p_apm_context = p_context;
    if( fr_slab_init( (Frmem_env *)(((ApmContext *)g_p_apm_context)->p_st_mem_env), MODULE_NAME) == NULL )
        return FR_FAIL;

    frlog_set_hd(((ApmContext *)g_p_apm_context)->p_st_log_category);
    p_module_cfg->p_l4_proto = MODULE_L4PROTO;
    p_module_cfg->i_l7_proto = MODULE_L7PROTO;
    p_module_cfg->p_module_name = MODULE_NAME;
    p_module_cfg->p_version = MODULE_VERSION " " MODULE_TIME;
    p_module_cfg->l7_detect = ora_detect;
    p_module_cfg->l7_analysis = ora_analyze;
    p_module_cfg->session_destory = ora_session_destory;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  oracle销毁
*  ARGS     :  void
*  RTN      :
*  NOTE     :
*******************************************************************************/
void module_exit(void)
{
    ORA_PRINT_INFO("ora_destroy run\n");
    __ora_print_dbg_info();
    fr_slab_destroy();
    return;
}

#ifdef  __cplusplus
}
#endif
